#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
ping_utils.py
--------------
Ubuntu/Linux 专用的多线程 Ping 工具模块。

提供接口：
    ping_hosts(ips, timeout=1.0, max_workers=20)
返回：
    {
        "192.168.10.1": {"online": True, "rtt_ms": 0.56},
        "192.168.10.23": {"online": False, "rtt_ms": None},
        ...
    }
"""

import subprocess
import re
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import Iterable, Dict
import time
from datetime import datetime


def _ping_once(ip: str, timeout: float = 1.0) -> dict:
    """
    执行一次 Ping 命令，返回是否在线及 RTT(ms)。
    :param ip: 目标 IP 地址或主机名
    :param timeout: 超时秒数
    :return: {"online": bool, "rtt_ms": float|None}
    """
    try:
        # 执行 ping 命令 (-c 1: 只发一个包, -W timeout: 超时)
        result = subprocess.run(
            ["ping", "-c", "1", "-W", str(int(timeout)), ip],
            capture_output=True, text=True
        )

        if result.returncode != 0:
            return {"online": False, "rtt_ms": None}

        # 用正则解析 RTT
        match = re.search(r'time[=<]\s*([\d.]+)\s*ms', result.stdout)
        rtt = float(match.group(1)) if match else None

        return {"online": True, "rtt_ms": rtt}

    except Exception:
        return {"online": False, "rtt_ms": None}


def ping_hosts(
    ips: Iterable[str],
    timeout: float = 1.0,
    max_workers: int = 20
) -> Dict[str, dict]:
    """
    并发检测多个 IP 是否在线并返回 RTT。

    :param ips: IP 地址或主机名列表
    :param timeout: 每个 Ping 的超时（秒）
    :param max_workers: 最大并发线程数
    :return: { "192.168.10.1": {"online": True, "rtt_ms": 0.56}, ... }
    """
    ip_list = list(dict.fromkeys(str(ip).strip() for ip in ips if str(ip).strip()))
    if not ip_list:
        return {}

    results: Dict[str, dict] = {}

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        future_map = {executor.submit(_ping_once, ip, timeout): ip for ip in ip_list}
        for future in as_completed(future_map):
            ip = future_map[future]
            try:
                results[ip] = future.result()
            except Exception:
                results[ip] = {"online": False, "rtt_ms": None}

    return results


# 测试入口（独立运行）
if __name__ == "__main__":
    test_ips = ["192.168.18.1", "8.8.8.8", "10.0.0.1"]
    print("开始持续网络检测（Ctrl+C 退出）...\n")

    try:
        while True:
            res = ping_hosts(test_ips, timeout=1.0)
            now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

            print(f"\n[{now}] 检测结果：")
            for ip, info in res.items():
                online = "✅ 在线" if info["online"] else "❌ 离线"
                rtt = f"{info['rtt_ms']:.2f} ms" if info["rtt_ms"] else "-"
                print(f"  {ip:15} {online:6} RTT: {rtt}")

            time.sleep(1)
    except KeyboardInterrupt:
        print("\n已停止检测。")
